package com.sleepingrain;

import java.io.IOException;
import java.util.List;
import java.util.Random;

import android.content.res.AssetManager;
import android.util.Log;

class RainGenerator extends SoundGenerator
{
	RainGenerator(SoundBuffer sb,SampleLib lib)
	{
		super(sb,lib);
		m_cache = new SoundGenCache(this,2000,500,100,500);
		m_soundBuffer.divisor = 100;
	}
	
	protected void resetDivisorAndCache()
	{
		m_cache.invalidate();
		m_soundBuffer.divisor = 100;
	}

	public void config_setCaching(boolean active)
	{
		m_cache.setCachingEnabled(active);
	}
	
	public void config_setIntensity(int progress)
	{
		beginConfig();
		//m_maxinterval = (int)(10010-100*intensity);
		m_maxinterval = (int)(10000*Math.pow((float)(progress-101)/100.0f,4.0f));
		resetDivisorAndCache();
		endConfig();
		Log.i("GenRain", "Set interval to: "+m_maxinterval+" Volume to: "+m_volume);
	}
	
	public void config_setRoomsize(int progress)
	{
		beginConfig();
		m_roomsize = 250*progress+50;
		resetDivisorAndCache();
		endConfig();
	}

	public void config_setStereoWidth(int progress)
	{
		beginConfig();
		m_stereoWidth = 2*progress;
		resetDivisorAndCache();
		endConfig();
	}

	public void config_setMinDistance(int progress)
	{
		beginConfig();
		m_minDistance = 10*progress+1;
		resetDivisorAndCache();
		endConfig();
	}

	public void config_setPitch(int progress)
	{
		beginConfig();
		m_pitch = progress;
		resetDivisorAndCache();
		endConfig();
	}
	
	public void config_setVolume(int progress)
	{
		if (m_cache.isCachingActive())
		{
			m_cache.setOutputVolume(progress / 5);
		} else {
			m_volume = (float)progress / 5.0f;
			Log.i("GenRain", "Set Volume to: "+m_volume);
			resetDivisorAndCache();
		}
	}

	protected void generate()
	{
		Sample s = m_sampleLib.get(m_rnd.nextInt(Math.max(1,m_pitch*m_sampleLib.size()/100)));
		if (s != null)
		{
			int x = m_rnd.nextInt(m_roomsize)-m_roomsize/2;
			int y = m_rnd.nextInt(m_roomsize)-m_roomsize/2;
			// Distance to the left ear
			double distL = Math.sqrt(x*x+y*y)+m_minDistance;
			// Stereo Basis
			x -= m_stereoWidth;
			// Distance to the right ear
			double distR = Math.sqrt(x*x+y*y)+m_minDistance;
			int delaySamples = (int)((double)m_soundBuffer.sampleRate()*(distR-distL)/(33000));   
			// Left Channel at time m_time
			m_time = m_cache.insertSample(0, m_time, s,0,s.sampleCount,(int)(m_volume*100.0*(double)m_minDistance/distL));
			// Right Channel at time m_time+delaySamples. if delaySamples > 0: distR > distL => delay must be positive
			m_cache.insertSample(1, m_time+delaySamples, s,0,s.sampleCount, (int)(m_volume*100.0*(double)m_minDistance/distR));
			m_time += m_rnd.nextInt(Math.max(1,m_maxinterval))+1;
		}
	}

	int m_time;
	private final Random m_rnd = new Random();
	int m_roomsize = 10000;
	int m_maxinterval = 10000;
	int m_minDistance = 50;
	int m_stereoWidth = 20;
	String m_assetPath;
	float m_volume = 1.0f;
	int m_pitch;
	SoundGenCache m_cache;
}

class PinkNoiseGen
{
	protected double nextValue() 
	{
		double x = rnd.nextDouble()-0.5;
		
		for (int i=0; i < poles; i++) {
			x -= multipliers[i] * values[i];
		}
		System.arraycopy(values, 0, values, 1, values.length-1);
		values[0] = x;
		
		return x;
	}

	public Sample prepareSample(int _poles,double alpha,int sampleRate,int lengthms)
	{
		poles = _poles;
		rnd = new Random();
		multipliers = new double[poles];
		values = new double[poles];
		double a = 1;
		for (int i=0; i < poles; i++) {
		    a = (i - alpha/2) * a / (i+1);
		    multipliers[i] = a;
		}
		
		// Fill the history with random values
		for (int i=0; i < 5*poles; i++)
		    this.nextValue();

		Sample s = new Sample(sampleRate,1,sampleRate*lengthms/1000);
		for (int i=0;i<s.sampleCount;++i)
		{
			s.samples[i] = (short)(1000.0*nextValue());
		}
		return s;
	}

	Random rnd;
	int poles;
	double multipliers[];
	double values[];
};

class ContinousGenerator extends SoundGenerator
{
	ContinousGenerator(SoundBuffer sb,SampleLib lib)
	{
		super(sb,lib);
		m_soundBuffer.divisor = 100;
	}

	public void config_setVolume(int progress)
	{
		m_volume = progress;
	}
	
	protected void generate()
	{
		Sample s = m_sampleLib.get(0);
		if (s != null)
		{
			int chunkSize = s.sampleCount / 10;
			for (int offset = 0;offset<s.sampleCount; offset += chunkSize)
			{
				int samplesToInsert = Math.min(chunkSize, s.sampleCount-offset);
				m_time = m_soundBuffer.insertSample(this, 0, m_time, s, offset, samplesToInsert, m_volume);
				m_time = m_soundBuffer.insertSample(this, 1, m_time, s, offset, samplesToInsert, m_volume);
				m_time += samplesToInsert;
			}
		}
	}
	int m_volume;
	int m_time;
}